/**
 * 子设备抽象层
 * 子设备抽象层，用于管理子设备的配置、状态、数据等信息。
 * 不操作具体的硬件，只提供统一的接口，方便上层应用调用。
 * 子设备抽象层的主要功能如下：
 * 1. 子设备配置管理：子设备配置管理模块用于管理子设备的配置信息，包括子设备的协议类型、端口号、地址、波特率、超时时间等。
 * 2. 子设备状态管理：子设备状态管理模块用于管理子设备的运行状态，包括子设备的连接状态、运行状态、运行模式等。
 * 3. 子设备数据管理：子设备数据管理模块用于管理子设备的运行数据，包括子设备的运行数据、运行数据更新时间、运行数据上报时间等。
 * 4. 子设备数据上报：子设备数据上报模块用于上报子设备的运行数据。
 */
#include <math.h>
#include "mlink.h"
#include "mlink_subdevice.h"

#define TAG "MLINK_SUBDEV"
#define DEVICE_SUBDEV_INFO_STORE_KEY         "subdev_info"

#define CHARACTERISTICS_MAX_NUM     (300)

static subdev_port_t *g_subdev_port[SUBDEV_PORT_MAX_NUM];


/**
 * @brief 打包value值json字符串
 * @param json_str 子设备json字符串
 * @param val_type 子设备value类型
 * @param val 子设备value值
 * @return MDF_OK
 */
int subdev_json_pack_value(char **json_str, char *val_type, cid_value_t *val){
	int ret = ESP_OK;
	if(strcmp(val_type, "u16") == 0){
		ret = mlink_json_pack(json_str, "value", val->value_u16);
	}
	else if(strcmp(val_type, "i16") == 0){
		ret = mlink_json_pack(json_str, "value", val->value_i16);
	}
	else if(strcmp(val_type, "u32") == 0 || strcmp(val_type, "u32CDAB") == 0){
		ret = mlink_json_pack(json_str, "value", val->value_u32);
	}
	else if(strcmp(val_type, "i32") == 0 || (strcmp(val_type, "i32CDAB") == 0)){
		ret = mlink_json_pack(json_str, "value", val->value_i32);
	}
	else if(strcmp(val_type, "float") == 0|| (strcmp(val_type, "fCDAB") == 0)){
		ret = mlink_json_pack_double(json_str, "value", val->value_float);
	}
	else {
		return ESP_FAIL;
	}
	return ret;
}

/**
 * @brief 解析value值json字符串
 * @param json_str 子设备json字符串
 * @param val_type 子设备value类型
 * @param val 子设备value值
 */
int subdev_json_parse_value(char *json_str, char *val_type, cid_value_t *val){
	int ret = ESP_OK;
	if(strcmp(val_type, "u16") == 0){
		ret = mlink_json_parse(json_str, "value", &val->value_u16);
	}
	else if(strcmp(val_type, "i16") == 0){
		ret = mlink_json_parse(json_str, "value", &val->value_i16);
	}
	else if(strcmp(val_type, "u32") == 0 || strcmp(val_type, "u32CDAB") == 0){
		ret = mlink_json_parse(json_str, "value", &val->value_u32);
	}
	else if(strcmp(val_type, "i32") == 0 || (strcmp(val_type, "i32CDAB") == 0)){
		ret = mlink_json_parse(json_str, "value", &val->value_i32);
	}
	else if(strcmp(val_type, "float") == 0|| (strcmp(val_type, "fCDAB") == 0)){
		ret = mlink_json_parse(json_str, "value", &val->value_float);
	}
	else {
		return ESP_FAIL;
	}
	return ret;
}

int mlink_del_subdev(uint8_t index);

/**
 * @brief mlink_add_subdev
 * @param config 子设备配置
 * @return 子设备句柄
 */
subdev_port_t *mlink_add_subdev(subdev_port_t *new_subdev) {
    if(new_subdev == NULL){
        return NULL;
    }
    int i=0;
    if(new_subdev->port_index >= SUBDEV_PORT_MAX_NUM){
        MDF_LOGW("The subdev index is out of range");
        return NULL;
    }
    if(g_subdev_port[new_subdev->port_index]!= NULL) {
        MDF_LOGW("The subdev index is already used, free old subdev first");
        mlink_del_subdev(new_subdev->port_index);
    }
    g_subdev_port[new_subdev->port_index] = new_subdev;
    return new_subdev;
}

/**
 * @brief 删除子设备
 * @param index 子设备索引
 * @return MDF_OK
 * */
int mlink_del_subdev(uint8_t index) {
    if(index >= SUBDEV_PORT_MAX_NUM){
        MDF_LOGW("The subdev index is out of range");
        return MDF_FAIL;
    }
    if(g_subdev_port[index] == NULL){
        MDF_LOGW("The subdev index is not used");
        return MDF_FAIL;
    }
    MDF_FREE(g_subdev_port[index]->cids);
    MDF_FREE(g_subdev_port[index]);
    g_subdev_port[index] = NULL;
    return MDF_OK;
}

/**
 * @brief 获取子设备句柄
 * @param index 子设备索引
 * @return 子设备句柄
*/
subdev_port_t *mlink_get_subdev_handle_by_index(uint8_t index) {
    if(index >= SUBDEV_PORT_MAX_NUM){
        MDF_LOGW("The subdev index is out of range");
        return NULL;
    }
    return g_subdev_port[index];
}

/**
 * @brief 生成子设备CID
 * @param cid 子设备cid名称
 * @param f 子设备cid值
 * @param type 子设备cid类型
 * @param update_time 子设备cid更新时间
 * @param report_time 子设备cid上报时间
 * @param max_inr 子设备cid最大电流值
 * @param change_val 子设备cid变化值
 * @return MDF_OK on success, MDF_FAIL on failure.
*/
mdf_err_t mlink_subdev_cid_init(subdev_cid_t *cid_handle, const char *cid, float f, const char *type, uint16_t max_inr, float change_val, char *name) {
	if(cid_handle == NULL){
		MDF_LOGW("Memory allocation failed");
		return NULL;
	}
	if(cid == NULL || strlen(cid) >= SUBDEV_CID_MAX_LEN){
		MDF_LOGW("The cid is invalid");
		return NULL;
	}
	if(type == NULL || strlen(type) >= SUBDEV_TYPE_MAX_LEN){
		MDF_LOGW("The type is invalid");
		return NULL;
	}

	cid_handle->f = f;
	strcpy(cid_handle->name, name);
	strcpy(cid_handle->cid, cid);
	strcpy(cid_handle->type, type);
	cid_handle->max_inr = max_inr;
	cid_handle->change_val = change_val;
	return MDF_OK;
}

/**
 * @brief 添加子设备cid
 * @param subdev 子设备句柄
 * @param cid 子设备cid
 * @return MDF_OK on success, MDF_FAIL on failure.
*/
mdf_err_t mlink_add_subdev_cid(subdev_port_t *subdev, subdev_cid_t *cid) {
    if(subdev == NULL || cid == NULL){
        return MDF_FAIL;
    }
    if(subdev->cids_num >= CHARACTERISTICS_MAX_NUM){
        MDF_LOGW("The subdev cids is full");
        return MDF_FAIL;
    }
    subdev->cids[subdev->cids_num] = *cid;
    subdev->cids_num++;
    return MDF_OK;
}


/**
 * @brief 获取子设备cid的句柄
 * @param subdev 子设备句柄
 * @param cid 子设备cid名称
 * @param index [out] 子设备cid索引
 * @return 子设备cid句柄
 */
subdev_cid_t *mlink_get_subdev_cid_handle_by_name(subdev_port_t *subdev, char *cid, int *index) {
    if(subdev == NULL || cid == NULL){
        return NULL;
    }
	int j=0;
	for( j=0; j<subdev->cids_num; j++) {

		if( strcmp(subdev->cids[j].cid, cid) == 0 ){
			if(index!= NULL){
				*index = j;
			}
			return &subdev->cids[j];
		}
	}

	return NULL;
}

/**
 * @brief 获取子设备cid的句柄
 * @param subdev 子设备句柄
 * @param cid 子设备cid索引
 * @return 子设备cid句柄
 */
subdev_cid_t *mlink_get_subdev_cid_handle_by_index(subdev_port_t *subdev, uint16_t index) {
    if(subdev == NULL){
        return NULL;
    }
    if(index >= subdev->cids_num){
        return NULL;
    }
	return &subdev->cids[index];
}

static int _parse_subdev_cids(char *src, subdev_port_t *out)
{
	esp_err_t ret	  = ESP_OK;
	char **addr_json=NULL;
	ssize_t addr_num = 0;
	char protocol_str[16] = {0};

	out->protocol = SUBDEV_PROTOCOL_NONE;
	ret = mlink_json_parse(src, "protocol", protocol_str);
	if(ret == MDF_OK && strlen(protocol_str) > 0){
		if(strcmp(protocol_str, CONST_STR_MODBUSTCP) == 0){
			out->protocol = SUBDEV_PROTOCOL_MODBUS_TCP;
		}else if(strcmp(protocol_str, CONST_STR_MODBUSUDP) == 0){
			out->protocol = SUBDEV_PROTOCOL_MODBUS_UDP;
		}else if(strcmp(protocol_str, CONST_STR_MODBUSRTU) == 0){
			out->protocol = SUBDEV_PROTOCOL_MODBUS_RTU;
		}else if(strcmp(protocol_str, CONST_STR_MODBUSASCII) == 0){
			out->protocol = SUBDEV_PROTOCOL_MODBUS_ASCII;
		}else if(strcmp(protocol_str, CONST_STR_DLT645_07) == 0){
			out->protocol = SUBDEV_PROTOCOL_DLT645_07;
		}else if(strcmp(protocol_str, CONST_STR_DLT645_97) == 0){
			out->protocol = SUBDEV_PROTOCOL_DLT645_97;
		}else if(strcmp(protocol_str, CONST_STR_CJT188_04) == 0){
			out->protocol = SUBDEV_PROTOCOL_CJT188_04;
		}else if(strcmp(protocol_str, CONST_STR_NONE) == 0){
			out->protocol = SUBDEV_PROTOCOL_NONE;
		}else{
			ESP_LOGW(TAG, "The protocol is not supported");
			return MDF_FAIL;
		}
	}

    out->poll_interval = 100;
	ret = mlink_json_parse(src, "poll_interval", &out->poll_interval);

	switch(out->protocol){
		case SUBDEV_PROTOCOL_DLT645_07:
		case SUBDEV_PROTOCOL_DLT645_97:
		case SUBDEV_PROTOCOL_CJT188_04:
		case SUBDEV_PROTOCOL_MODBUS_RTU:
		case SUBDEV_PROTOCOL_MODBUS_ASCII:
			ret = mlink_json_parse(src, "serial", &out->info_union.serial.uart_num);
			MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
			break;
		case SUBDEV_PROTOCOL_MODBUS_TCP:
		case SUBDEV_PROTOCOL_MODBUS_UDP:{
			out->info_union.modbus_tcp.slave_num = 0;
			ret = mlink_json_parse(src, "slave_ip", &(out->info_union.modbus_tcp.slave_num));
			MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");

			if(out->info_union.modbus_tcp.slave_num == 0){
				ESP_LOGW(TAG, "The slave_ip is empty");
				break;
			}
			out->info_union.modbus_tcp.slave_ip = calloc(out->info_union.modbus_tcp.slave_num, sizeof(char *));
			assert(out->info_union.modbus_tcp.slave_ip);
			
			ret = mlink_json_parse(src, "slave_ip", out->info_union.modbus_tcp.slave_ip);
			MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");

			ret = mlink_json_parse(src, "slave_port", &out->info_union.modbus_tcp.slave_port);
			MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
			break;
		}
		default:
			break;
	}

	ret = mlink_json_parse(src, "cids", &addr_num);
	MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
	
	if(addr_num > 0){

		addr_json = calloc(addr_num, sizeof(char *));
		assert(addr_json);
		
		ret = mlink_json_parse(src, "cids", addr_json);
		MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
	
		out->cids_num = addr_num;
		out->cids = calloc(addr_num, sizeof(subdev_cid_t));
		for (int i = 0; i < addr_num; ++i) {
			subdev_cid_t subdev_cid;
			memset(&subdev_cid, 0, sizeof(subdev_cid_t));
			subdev_cid.change_val = 1;
			subdev_cid.error = 1;

			ret = mlink_json_parse(addr_json[i], "name", subdev_cid.name);
			// MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
			
			ret = mlink_json_parse(addr_json[i], "cid", subdev_cid.cid);
			MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
			if(strlen(subdev_cid.cid) == 0) {
				ESP_LOGW(TAG, "The cid is empty");
				ret = MDF_ERR_INVALID_ARG;
				goto EXIT;
			}

			ret = mlink_json_parse(addr_json[i], "f", &subdev_cid.f);
			MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");

			ret = mlink_json_parse(addr_json[i], "type", subdev_cid.type);
			MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
			if(strstr(subdev_cid.type, "float") != NULL || strstr(subdev_cid.type, "fCDAB") != NULL){
				subdev_cid.value.value_float = 0;
			}
			// mlink_json_parse(addr_json[i], "min_inr", &subdev_cid.min_inr);

			mlink_json_parse(addr_json[i], "max_inr", &subdev_cid.max_inr);

			mlink_json_parse(addr_json[i], "change_val", &subdev_cid.change_val);

			// 解析成功
			memcpy(&out->cids[i], &subdev_cid, sizeof(subdev_cid_t));
		}
		
		for (int i = 0; i < addr_num; ++i) {
			MDF_FREE(addr_json[i]);
		}
		MDF_FREE(addr_json);

	}

	return ret;
	
EXIT:
	if(addr_num > 0){
		MDF_FREE(out->cids);
		for (int i = 0; i < addr_num; ++i) {
			MDF_FREE(addr_json[i]);
		}
		MDF_FREE(addr_json);

	}
	return ret;
}

static esp_err_t mlink_handle_subdev_set_cids(mlink_handle_data_t *handle_data)
{
	esp_err_t ret	  = ESP_OK;
	char node[4];

	ret = mlink_json_parse(handle_data->req_data, "node", node);
	MDF_ERROR_CHECK(ret != MDF_OK, ESP_ERR_INVALID_ARG, "Parse the json formatted string");
    
	uint8_t index = atoi(&(node[1]));
	if(index >= sizeof(g_subdev_port)/sizeof(g_subdev_port[0])){
		ret = ESP_FAIL;
		return ret;
	}
	// 解析数据 判断格式错误
	subdev_port_t *subdev = MDF_CALLOC(1, sizeof(subdev_port_t));
    subdev->port_index = index;
	ret = _parse_subdev_cids(handle_data->req_data, subdev);
	if(ret != MDF_OK){
		MDF_FREE(subdev);
		return ret;
	}

	char save_name[16];
	sprintf(save_name, DEVICE_SUBDEV_INFO_STORE_KEY"_%s", node);
	
	// if cid is empty, erase the info
	if(subdev->cids_num == 0){
		ret = mdf_info_erase(save_name);
		return ret;
	}
	// save the info
    if(NULL == mlink_add_subdev(subdev)) {
		MDF_FREE(subdev);
		return ESP_FAIL;
    }
	mdf_info_erase(save_name);
	ret = mdf_info_save(save_name, handle_data->req_data, strlen(handle_data->req_data)+1);
	return ret;
}

static esp_err_t mlink_handle_subdev_get_cids(mlink_handle_data_t *handle_data)
{
	int ret = ESP_OK;
	char node[4];

	ret = mlink_json_parse(handle_data->req_data, "node", node);
	MDF_ERROR_CHECK(ret != MDF_OK, ESP_ERR_INVALID_ARG, "Parse the json formatted string");
	uint8_t index = atoi(&(node[1]));
	if(index >= sizeof(g_subdev_port)/sizeof(g_subdev_port[0])){
		ret = ESP_FAIL;
		return ret;
	}
	subdev_port_t *subdev = mlink_get_subdev_handle_by_index(index);
    if(subdev == NULL){
        ret = ESP_FAIL;
        return ret;
    }
	mlink_json_pack(&handle_data->resp_data, "node", node);
	if(subdev->protocol == SUBDEV_PROTOCOL_MODBUS_TCP){
		mlink_json_pack(&handle_data->resp_data, "protocol", CONST_STR_MODBUSTCP);
	} else if(subdev->protocol == SUBDEV_PROTOCOL_MODBUS_UDP){
		mlink_json_pack(&handle_data->resp_data, "protocol", CONST_STR_MODBUSUDP);
	} else if(subdev->protocol == SUBDEV_PROTOCOL_MODBUS_RTU){
		mlink_json_pack(&handle_data->resp_data, "protocol", CONST_STR_MODBUSRTU);
	} else if(subdev->protocol == SUBDEV_PROTOCOL_MODBUS_ASCII){
		mlink_json_pack(&handle_data->resp_data, "protocol", CONST_STR_MODBUSASCII);
	} else if(subdev->protocol == SUBDEV_PROTOCOL_DLT645_07){
		mlink_json_pack(&handle_data->resp_data, "protocol", CONST_STR_DLT645_07);
	} else if(subdev->protocol == SUBDEV_PROTOCOL_DLT645_97){
		mlink_json_pack(&handle_data->resp_data, "protocol", CONST_STR_DLT645_97);
	} else if(subdev->protocol == SUBDEV_PROTOCOL_CJT188_04){
		mlink_json_pack(&handle_data->resp_data, "protocol", CONST_STR_CJT188_04);
	} else if(subdev->protocol == SUBDEV_PROTOCOL_NONE){
		mlink_json_pack(&handle_data->resp_data, "protocol", CONST_STR_NONE);
	}
	if(subdev->protocol == SUBDEV_PROTOCOL_MODBUS_TCP || subdev->protocol == SUBDEV_PROTOCOL_MODBUS_UDP){
		char *slave_ip=NULL;
		for(int i=0; i <subdev->info_union.modbus_tcp.slave_num; i++) {
			mlink_json_pack(&slave_ip, "[]", subdev->info_union.modbus_tcp.slave_ip[i]);
		}
		mlink_json_pack(&handle_data->resp_data, "slave_ip", slave_ip);
		if(slave_ip)free(slave_ip);
		mlink_json_pack(&handle_data->resp_data, "slave_port", subdev->info_union.modbus_tcp.slave_port);
	}
	else if(subdev->protocol == SUBDEV_PROTOCOL_CJT188_04
			|| subdev->protocol == SUBDEV_PROTOCOL_DLT645_07
			|| subdev->protocol == SUBDEV_PROTOCOL_DLT645_97
			|| subdev->protocol == SUBDEV_PROTOCOL_MODBUS_RTU
			|| subdev->protocol == SUBDEV_PROTOCOL_MODBUS_ASCII){
		mlink_json_pack(&handle_data->resp_data, "serial", subdev->info_union.serial.uart_num);
	}
	handle_data->resp_size = mlink_json_pack(&handle_data->resp_data, "poll_interval", subdev->poll_interval);
	char *cids = NULL;
	for(int i=0; i < subdev->cids_num; i++){
		char *item=NULL;
		mlink_json_pack(&item, "name", subdev->cids[i].name);
		mlink_json_pack(&item, "cid", subdev->cids[i].cid);
		mlink_json_pack_double(&item, "f", subdev->cids[i].f);
		mlink_json_pack(&item, "type", subdev->cids[i].type);
		mlink_json_pack(&item, "max_inr", subdev->cids[i].max_inr);
		mlink_json_pack_double(&item, "change_val", subdev->cids[i].change_val);
		mlink_json_pack(&cids, "[]", item);
		MDF_FREE(item);
	}
	if(cids){
		handle_data->resp_size = mlink_json_pack(&handle_data->resp_data, "cids", cids);
		MDF_FREE(cids);
	}
		
    return ret;
}

/**
 * @brief 设置子设备cid的值
 * 
 * @param subdev 子设备句柄
 * @param cid 子设备cid名称
 * @param value 子设备cid值
 * @return int 0:成功，其他:失败
*/
int mlink_subdev_set_cache_value(subdev_cid_t *cid_handle, void *value) {
	if(cid_handle == NULL || value == NULL) {
		return MDF_FAIL;
	}
	if(strstr(cid_handle->type, "u16")  != NULL){
		cid_handle->value.value_u16 = *(uint16_t *)value;
	} else if(strstr(cid_handle->type, "u32") != NULL){
		cid_handle->value.value_u32 =*(uint32_t *)value;
	} else if(strstr(cid_handle->type, "i16")  != NULL){
		cid_handle->value.value_i16 =*(int16_t *)value;
	} else if(strstr(cid_handle->type, "i32")  != NULL){
		cid_handle->value.value_i32 = *(int32_t *)value;
	} else if(strstr(cid_handle->type, "float")  != NULL
	|| strcmp(cid_handle->type, "fCDAB") == 0){
		cid_handle->value.value_float = *(float *)value;
	}
	return MDF_OK;
}

/**
 * @brief 获取子设备cid的值
 * 
 * @param subdev 子设备句柄
 * @param cid 子设备cid名称
 * @param value 子设备cid值
 * @return int 0:成功，其他:失败
 */
int mlink_subdev_get_cache_value(subdev_cid_t *cid_handle, void *value) {
	if(cid_handle == NULL || value == NULL) {
		return MDF_FAIL;
	}
	if(strstr(cid_handle->type, "u16") != NULL){
		*(uint16_t *)value = cid_handle->value.value_u16;
	} else if(strstr(cid_handle->type, "u32") != NULL){
		*(uint32_t *)value = cid_handle->value.value_u32;
	} else if(strstr(cid_handle->type, "i16") != NULL){
		*(int16_t *)value = cid_handle->value.value_i16;
	} else if(strstr(cid_handle->type, "i32") != NULL){
		*(int32_t *)value = cid_handle->value.value_i32;
	} else if(strstr(cid_handle->type, "float") != NULL || strcmp(cid_handle->type, "fCDAB") == 0){
		*(float *)value = cid_handle->value.value_float;
	}
	return MDF_OK;
}

/**
 * @brief 子设备cid值是否发生变化
 * 
 * @param subdev 子设备句柄
 * @param value 子设备cid值
 * @return int 0:没有变化，1:变化
 **/
int mlink_subdev_compare_change_value(subdev_cid_t *cid_handle, void *value) {
	if(cid_handle == NULL || value == NULL) {
		ESP_LOGI(TAG, "compare_change_value cid_handle or value is NULL");
		return 0;
	}
	// ESP_LOGI(TAG, "%s change_val=%f", cid_handle->cid, cid_handle->change_val);
	if(cid_handle->change_val == 0){
		return 0;
	}
	if(strstr(cid_handle->type, "u16") != NULL){
		return abs(cid_handle->value.value_u16 - *(uint16_t *)value) >= cid_handle->change_val ? 1 : 0;
	} else if(strstr(cid_handle->type, "u32") != NULL){
		return abs(cid_handle->value.value_u32 - *(uint32_t *)value) >= cid_handle->change_val ? 1 : 0;
	} else if(strstr(cid_handle->type, "i16") != NULL){
		return abs(cid_handle->value.value_i16 - *(int16_t *)value) >= cid_handle->change_val ? 1 : 0;
	} else if(strstr(cid_handle->type, "i32") != NULL){
		// ESP_LOGI(TAG, "abs=%d", abs(cid_handle->value.value_i32 - *(int32_t *)value));
		return abs(cid_handle->value.value_i32 - *(int32_t *)value) >= cid_handle->change_val ? 1 : 0;
	} else if(strstr(cid_handle->type, "float") != NULL || strcmp(cid_handle->type, "fCDAB") == 0){
		return fabsf(cid_handle->value.value_float - *(float *)value) >= cid_handle->change_val ? 1 : 0;
	}
	return 0;
}

/**
 * @brief 子设备cid是否达到最大上报间隔
 * 
 * @param subdev 子设备句柄
 * @param now 当前时间
 * @return int 0:没有达到，1:达到
 **/
int mlink_subdev_check_max_inr(subdev_cid_t *cid_handle, time_t now) {
	if(cid_handle == NULL) {
		ESP_LOGI(TAG, "check_max_inr cid_handle is NULL");
		return 0;
	}
	// ESP_LOGI(TAG, "check_max_inr %s max_inr=%d now-report_time=%d", cid_handle->cid, (int)cid_handle->max_inr, (int)(now-cid_handle->report_time));
	// 周期上报处理
	if(cid_handle->max_inr > 0) {
		if((now - cid_handle->report_time) >= cid_handle->max_inr){
			return 1;
		}
	}
	return 0;
}

void mlink_subdev_load_form_flash(void) {
    #define SUBDEV_BUFFER_SIZE (20*1024)
	char *temp_str = MDF_MALLOC(SUBDEV_BUFFER_SIZE);
	assert(temp_str);
	char save_name[16];
	for(int i=0; i<SUBDEV_PORT_MAX_NUM; i++){
		
		sprintf(save_name, DEVICE_SUBDEV_INFO_STORE_KEY"_n%d", i);

		int length=SUBDEV_BUFFER_SIZE;
		// length 传入缓存size，传出实际数据size
		if(mdf_info_load(save_name, temp_str, &length) == MDF_OK){
			temp_str[length] = 0;
			// ESP_LOGI(TAG, "Load %s cids:%s", save_name, temp_str);

            subdev_port_t *subdev = MDF_CALLOC(1, sizeof(subdev_port_t));
            subdev->port_index = i;
            if(MDF_OK != _parse_subdev_cids(temp_str, subdev)) {
                MDF_FREE(subdev);
                continue;
            }
            
            if(NULL == mlink_add_subdev(subdev)) {
                ESP_LOGW(TAG, "Add subdev %d fail", i);
                MDF_FREE(subdev->cids);
                MDF_FREE(subdev);
            }
		}
	}
	MDF_FREE(temp_str);
}

int mlink_subdev_handle_init(void) {
	mlink_set_handle("subdev_set_cids", mlink_handle_subdev_set_cids);
	mlink_set_handle("subdev_get_cids", mlink_handle_subdev_get_cids);
	// mlink_set_handle("subdev_get_cache", mlink_handle_subdev_get_cache);
	// mlink_set_handle("subdev_get_data", mlink_handle_subdev_get_data);
	// mlink_set_handle("subdev_set_data", mlink_handle_subdev_set_data);
	return MDF_OK;
}
